/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using MyPhotoIndex.Interfaces;

namespace MyPhotoIndex
{
    sealed class ActiveProcesses : Singleton<ActiveProcesses>, IEnumerable<ActiveProcess>
    {
        public event EventHandler FirstProcessAddedEvent;
        public event EventHandler ProcessAddedEvent;
        public event EventHandler ProcessRemovedEvent;
        public event EventHandler LastProcessRemovedEvent;
        public event EventHandler<ProcessInfoAlertParameters> ProcessAlertEvent;

        private static Dictionary<int, ActiveProcess> m_activeProcesses = new Dictionary<int, ActiveProcess>();
        private static List<ActiveProcess> m_activeProcessesList = new List<ActiveProcess>();
        private static object m_syncLock = new object();

        public ActiveProcess Get(int id)
        {
            lock (m_syncLock)
            {
                if (m_activeProcesses.ContainsKey(id))
                {
                    ActiveProcess activeProcess = m_activeProcesses[id];
                    activeProcess.LastAccessed = DateTime.Now;
                    return activeProcess;
                }
                else
                {
                    ActiveProcess activeProcess = new ActiveProcess();
                    activeProcess.ProcessId = id;
                    m_activeProcesses.Add(id, activeProcess);
                    m_activeProcessesList.Add(activeProcess);

                    if (m_activeProcesses.Count == 1)
                    {
                        if (FirstProcessAddedEvent != null)
                        {
                            FirstProcessAddedEvent.Invoke(this, EventArgs.Empty);
                        }
                    }
                    else
                    {
                        if (ProcessAddedEvent != null)
                        {
                            ProcessAddedEvent.Invoke(this, EventArgs.Empty);
                        }
                    }

                    activeProcess.AlertEvent += new EventHandler<ProcessInfoAlertParameters>(activeProcess_AlertEvent);
                    activeProcess.LastAccessed = DateTime.Now;
                    return activeProcess;
                }
            }
        }

        void activeProcess_AlertEvent(object sender, ProcessInfoAlertParameters e)
        {
            if (ProcessAlertEvent != null)
            {
                ProcessAlertEvent.Invoke(this, e);
            }
        }

        public ActiveProcess this[int index]
        {
            get
            {
                return m_activeProcessesList[index];
            }
        }

        public static int Count
        {
            get
            {
                return m_activeProcessesList.Count;
            }
        }

        public void Clear()
        {
            lock (m_syncLock)
            {
                List<int> ids = new List<int>();
                foreach (ActiveProcess proc in m_activeProcesses.Values)
                {
                    TimeSpan interval = DateTime.Now - proc.LastAccessed;
                    if (proc.Running == false &&
                        interval.TotalSeconds > 10)
                    {
                        ids.Add(proc.ProcessId);
                    }
                }

                foreach (int id in ids)
                {
                    ActiveProcess proc = m_activeProcesses[id];
                    m_activeProcessesList.Remove(proc);
                    m_activeProcesses.Remove(id);

                    if (m_activeProcesses.Count > 0)
                    {
                        if (ProcessRemovedEvent != null)
                        {
                            ProcessRemovedEvent.Invoke(this, EventArgs.Empty);
                        }
                    }
                    else
                    {
                        if (LastProcessRemovedEvent != null)
                        {
                            LastProcessRemovedEvent.Invoke(this, EventArgs.Empty);
                        }
                    }
                }
            }
        }

        #region IEnumerable<ActiveProcess> Members

        public IEnumerator<ActiveProcess> GetEnumerator()
        {
            return m_activeProcessesList.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }
}
